import hashlib
import json
import re
import datetime
import requests
import time
import frappe


class WDTAPIException(Exception):
    """
    旺店通API异常类
    """
    def __init__(self, message, response_data=None):
        super().__init__(message)
        self.message = message
        self.response_data = response_data

    def __str__(self):
        if self.response_data:
            return f"{self.message} - 响应数据: {self.response_data}"
        return self.message


class WMSWDTClient:
    def __init__(self):


#以下是旺店通公司测试环境
        self.host = "https://wmsapi.wdtwms.com/wms_api/wdt_service.php"
        self.appKey = "wdt17557478145662"
        self.appSecret = "2890230b5629566b935836a12d5a5c12"
        self.sid = "wms_lt2_flowaWDT"

#以下是龙琪仓正式环境
        self.host = "https://wmsapi.wdtwms.com/wms_api/wdt_service.php"
        self.appKey = "wdt17590499737112"
        self.appSecret = "e1a046857bd844da42c30292c7b33166"
        self.sid = "wms_lt2_flowa01WDT"

        self.session = requests.Session()

    def _generate_url(self,params, body):
        params["appkey"] = self.appKey
        params["sign_method"] = "md5"
        params["timestamp"] = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
        params["sid"] = self.sid

        if params["format"]=="xml":
            xml_body = self._dict_to_xml(body)
            body = f"<request>{xml_body}</request>"
            frappe.logger().debug(f"WDT 最终XML请求体: {body}")
        elif params["format"]=="json":
            body = json.dumps(body, ensure_ascii=False)
            frappe.logger().debug(f"WDT JSON请求体: {body}")
        # 按照旺店通官方示例的签名算法
        sign_str = self.appSecret
        frappe.logger().debug(f"WDT签名开始，appSecret: {self.appSecret}")

        # 第一步：将公共参数的字段名字按字典序从小到大排序
        sorted_params = sorted(params.items())
        frappe.logger().debug(f"WDT排序后参数: {sorted_params}")

        # 第二步：拼接排序后的公共参数（过滤空值和sign参数）
        for key, value in sorted_params:
            if key != "sign" and value != "":
                sign_str += key
                sign_str += str(value)
                frappe.logger().debug(f"WDT添加参数: {key}={value}")

        # 第三步：添加请求体
        if body:
            sign_str += body
            frappe.logger().debug(f"WDT添加请求体: {body}")

        # 第四步：在末尾添加appSecret
        sign_str += self.appSecret
        frappe.logger().debug(f"WDT添加末尾appSecret后签名字符串: {sign_str}")

        # 第五步：去除字符串中的空白字符（按照官方示例）
        sign_str = re.sub(r'\s*', '', sign_str)
        frappe.logger().debug(f"WDT去除空字符后签名字符串: {sign_str}")

        # 第六步：生成32位MD5大写签名值
        md5_hash = hashlib.md5(sign_str.encode('utf-8')).hexdigest().upper()
        params["sign"] = md5_hash
        url_params = self._dict_to_url_params(params)
        final_url = self.host + '?' + url_params
        frappe.logger().debug(f"WDT最终请求URL: {final_url}")
        return final_url

    def _dict_to_xml(self,data, parent_key=''):
        xml_parts = []
        if isinstance(data, dict):
            for key, value in data.items():
                if isinstance(value, (dict, list)):
                    # 递归处理嵌套字典或列表
                    xml_parts.append(f"<{key}>{self._dict_to_xml(value, key)}</{key}>")
                else:
                    # 处理普通键值对
                    xml_parts.append(f"<{key}>{value}</{key}>")
        elif isinstance(data, list):
            for item in data:
                if isinstance(item, dict):
                    # 根据父键决定使用什么标签
                    if parent_key == "orderLines":
                        # orderLines下的项目使用orderLine标签，直接处理字段
                        order_line_xml = []
                        for field_key, field_value in item.items():
                            if field_value is not None and field_value != "":
                                order_line_xml.append(f"<{field_key}>{field_value}</{field_key}>")
                            else:
                                order_line_xml.append(f"<{field_key}/>")
                        xml_parts.append(f"<orderLine>{''.join(order_line_xml)}</orderLine>")
                    elif parent_key == "items":
                        # items下的项目使用item标签
                        xml_parts.append(f"<item>{self._dict_to_xml(item)}</item>")
                    elif parent_key == "criteriaList":
                        # criteriaList下的项目使用criteria标签
                        xml_parts.append(f"<criteria>{self._dict_to_xml(item)}</criteria>")
                    else:
                        # 默认使用item标签
                        xml_parts.append(f"<item>{self._dict_to_xml(item)}</item>")
                else:
                    # 列表中的简单值
                    xml_parts.append(f"<item>{item}</item>")
        else:
            # 简单值
            return str(data)
        return ''.join(xml_parts)

    def _dict_to_form_data(self, data):
        form_data_parts = []
        for key, value in data.items():
            if isinstance(value, str) and ' ' in value:
                # 如果值包含空格，将空格替换为+
                formatted_value = value.replace(' ', '+')
            else:
                formatted_value = str(value)
            form_data_parts.append(f"{key}={formatted_value}")

        return "&".join(form_data_parts)
    def _dict_to_url_params(self, data):
        # 按照旺店通官方示例的URL参数构建方式
        url_params = ""
        for key, value in data.items():
            url_params += "&"
            url_params += key
            url_params += "="
            if "timestamp" == key:
                # 时间戳特殊处理，空格替换为%20
                url_params += str(value).replace(" ", "%20")
                continue
            url_params += str(value)
        return url_params.lstrip("&")

    def _xml_to_dict(self, xml_string):
        """
        将XML字符串转换为字典

        Args:
            xml_string (str): XML格式字符串

        Returns:
            dict: 转换后的字典
        """
        import xml.etree.ElementTree as ET
        from xml.etree.ElementTree import ParseError

        try:
            # 解析XML字符串
            root = ET.fromstring(xml_string)

            def _element_to_dict(element):
                result = {}

                # 处理元素的子元素
                for child in element:
                    # 如果子元素有子元素，递归处理
                    if len(child) > 0:
                        child_data = _element_to_dict(child)
                        # 如果该键已存在，转换为列表
                        if child.tag in result:
                            if not isinstance(result[child.tag], list):
                                result[child.tag] = [result[child.tag]]
                            result[child.tag].append(child_data)
                        else:
                            result[child.tag] = child_data
                    else:
                        # 叶子节点，直接获取文本内容
                        # 如果该键已存在，转换为列表
                        if child.tag in result:
                            if not isinstance(result[child.tag], list):
                                result[child.tag] = [result[child.tag]]
                            result[child.tag].append(child.text or '')
                        else:
                            result[child.tag] = child.text or ''

                return result

            # 如果根元素有子元素，则返回子元素的字典
            if len(root) > 0:
                result = _element_to_dict(root)
                frappe.logger().debug(f"XML解析结果: {result}")
                return result
            else:
                # 如果根元素没有子元素，直接返回根元素的文本
                return {root.tag: root.text or ''}

        except ParseError as e:
            # XML解析错误时返回空字典或抛出异常
            frappe.logger().error(f"WDT XML解析错误: {e}")
            frappe.logger().error(f"XML内容: {xml_string[:500]}...")  # 显示前500个字符
            frappe.logger().error(f"XML原始内容长度: {len(xml_string)}")
            return {"error": "XML解析失败", "raw_response": xml_string, "parse_error": str(e)}
        except Exception as e:
            # 其他错误
            frappe.logger().error(f"WDT XML转换过程中发生错误: {e}")
            frappe.logger().error(f"XML内容: {xml_string[:500]}...")
            frappe.logger().error(f"XML原始内容长度: {len(xml_string)}")
            return {"error": "XML转换失败", "raw_response": xml_string, "exception": str(e)}
    def _request(self, params=None, data=None, max_retries=3, timeout=30):
        """
        发送请求到旺店通API

        Args:
            params: 请求参数
            data: 请求体数据
            max_retries: 最大重试次数
            timeout: 请求超时时间(秒)

        Returns:
            dict: API响应结果

        Raises:
            WDTAPIException: API调用异常
        """
        if not params or not data:
            raise ValueError("请求参数和请求体不能为空")

        header = {
            "Content-Type": "application/json",
        }

        try:
            url = self._generate_url(params, data)
            if params["format"] == "xml":
                header["Content-Type"] = "text/xml"
                xml_content = self._dict_to_xml(data)
                data = f"<request>{xml_content}</request>"

                # 打印完整的XML格式到调试日志
                frappe.logger().debug("=== 旺店通API完整XML请求内容 ===")
                frappe.logger().debug(f"XML请求体: {data}")
                frappe.logger().debug(f"XML内容长度: {len(data)} 字符")
                frappe.logger().debug(f"XML内容类型: {type(data)}")

                # 格式化打印XML（便于阅读）
                import xml.dom.minidom
                try:
                    formatted_xml = xml.dom.minidom.parseString(data).toprettyxml(indent="  ")
                    frappe.logger().debug("=== 格式化后的XML内容 ===")
                    frappe.logger().debug(f"{formatted_xml}")
                except Exception as e:
                    frappe.logger().warning(f"XML格式化失败: {e}")
                    frappe.logger().debug(f"原始XML内容: {data}")

            if params["format"] == "json":
                data = json.dumps(data, ensure_ascii=False)

            frappe.logger().debug("=== WDT HTTP请求详细信息 ===")
            frappe.logger().debug(f"WDT API请求URL: {url}")
            frappe.logger().debug(f"WDT API请求参数: {params}")
            frappe.logger().debug(f"WDT API请求体: {data}")
            frappe.logger().debug(f"WDT API请求头: {header}")
            frappe.logger().debug(f"WDT API请求体长度: {len(data) if data else 0}")
            frappe.logger().debug(f"WDT API请求体类型: {type(data)}")

            # 重试机制
            for attempt in range(max_retries):
                try:
                    r = self.session.post(url=url, headers=header, data=data, timeout=timeout)

                    # 记录HTTP响应详情
                    frappe.logger().debug("=== WDT HTTP响应详细信息 ===")
                    frappe.logger().debug(f"WDT API HTTP状态码: {r.status_code}")
                    frappe.logger().debug(f"WDT API响应头: {dict(r.headers)}")
                    frappe.logger().debug(f"WDT API响应内容: {r.text}")  # 显示完整响应内容

                    # 检查HTTP状态码
                    r.raise_for_status()

                    # 解析响应
                    if params["format"] == "xml":
                        response_data = self._xml_to_dict(r.text)
                        frappe.logger().debug(f"WDT XML解析后数据结构: {response_data}")
                    else:
                        response_data = r.json()

                    # 检查业务状态码 - 旺店通API: code=""表示成功，有值表示失败
                    if isinstance(response_data, dict):
                        code = response_data.get("code")
                        frappe.logger().debug(f"WDT 检查业务状态码: code={code}, 类型={type(code)}")

                        # 旺店通约定: code 为空或 "0" 表示成功，其余视为业务错误
                        if code is not None and str(code) not in ("", "0"):
                            error_msg = response_data.get("message", "未知业务错误")
                            frappe.logger().error(f"WDT 业务错误: {error_msg}")
                            # 直接抛出业务错误信息，不包装额外的文本
                            raise WDTAPIException(f"业务错误: {error_msg}", response_data)

                    frappe.logger().info(f"WDT API请求成功: {response_data}")
                    return response_data

                except requests.exceptions.Timeout:
                    frappe.logger().warning(f"WDT API请求超时 (尝试 {attempt + 1}/{max_retries})")
                    if attempt == max_retries - 1:
                        raise WDTAPIException("请求超时，已达到最大重试次数")
                    time.sleep(2 ** attempt)  # 指数退避

                except requests.exceptions.ConnectionError:
                    frappe.logger().warning(f"WDT API连接错误 (尝试 {attempt + 1}/{max_retries})")
                    if attempt == max_retries - 1:
                        raise WDTAPIException("连接错误，已达到最大重试次数")
                    time.sleep(2 ** attempt)

                except requests.exceptions.HTTPError as e:
                    frappe.logger().error(f"WDT API HTTP错误: {e}")
                    frappe.logger().error(f"HTTP响应状态码: {r.status_code}")
                    frappe.logger().error(f"HTTP响应内容: {r.text[:1000]}...")
                    raise WDTAPIException(f"HTTP错误: {e}")

                except json.JSONDecodeError as e:
                    frappe.logger().error(f"WDT API JSON解析错误: {e}")
                    frappe.logger().error(f"响应内容: {r.text[:1000]}...")
                    raise WDTAPIException(f"响应数据格式错误: {e}")

        except Exception as e:
            frappe.logger().error(f"WDT API请求异常: {e}")
            frappe.logger().error(f"异常类型: {type(e).__name__}")
            import traceback
            frappe.logger().error(f"异常堆栈: {traceback.format_exc()}")
            raise WDTAPIException(f"请求异常: {e}")
    # ==================== 优先实现的高频接口 ====================

    def wdt_wms_entryorder_create(self, entryorder_data):
        """
        入库单创建接口 - WDT_WMS_ENTRYORDER_CREATE
        方向: ERP→WMS
        严格按照旺店通接口文档实现

        参数结构:
        entryorder_data = {
            "entryOrder": {
                "entryOrderCode": "入库单号,varchar(50),必填,唯一值",
                "warehouseCode": "仓库编码,varchar(50),必填",
                "orderType": "入库类型(CGRK=采购入库;DBRK=调拨入库;QTRK=其他入库;B2BRK=B2B入库(唯品入库);SCRK=生产入库),string,必填",
                "supplierCode": "供应商编号(orderType=CGRK时接收该信息),varchar(30)",
                "supplierName": "供应商(orderType=CGRK时接收该信息),varchar(100)",
                "logisticsName": "物流公司,varchar(40)",
                "expressCode": "物流单号,varchar(40)",
                "remark": "单据备注,varchar(255)",
                "senderInfo": {
                    "name": "发货人姓名,varchar(40)",
                    "tel": "发货人固话,varchar(32)",
                    "mobil": "发货人手机号,varchar(30)",
                    "detailAddress": "发货人地址,varchar(255)"
                },
                "extendProps": {
                    "vphRefundNo": "唯品会退货单号(orderType=B2BRK时必填),varchar(50)",
                    "receipt_type": "自定义属性1,varchar(255)",
                    "prop2_code": "自定义属性2,varchar(255)",
                    "supplierMsg": "自定义属性3,varchar(255)",
                    "prop4_code": "自定义属性4,varchar(255)",
                    "prop5_code": "自定义属性5,varchar(255)",
                    "prop6_code": "自定义属性6,varchar(255)",
                    "purchaserName": "采购员(orderType=CGRK时接收该信息),varchar(40)"
                }
            },
            "orderLines": [
                {
                    "orderLineNo": "单据行号(订单中同一货品有多条记录时必填,保证同一个货品的orderLineNo不同),varchar(50)",
                    "itemCode": "商家编码,varchar(50),必填",
                    "itemName": "货品名称,varchar(255)",
                    "planQty": "开单数量,decimal(19,4),必填",
                    "purchasePrice": "采购单价(orderType=CGRK时接收该信息),decimal(19,4)",
                    "inventoryType": "是否正品(ZP=正品;CC=残次;默认为ZP,只传英文编码),string",
                    "productDate": "生产日期(YYYY-MM-DD HH:MM:SS),datetime",
                    "expireDate": "有效期(YYYY-MM-DD HH:MM:SS),datetime",
                    "batchCode": "批次,varchar(50)",
                    "remark": "货品备注,varchar(512)",
                    "extendProps": {
                        "VpPackageNO": "唯品会PO单号(orderType=B2BRK时必填),varchar(50)",
                        "VpBoxNO": "唯品会入库箱号(orderType=B2BRK时必填),varchar(50)"
                    }
                }
            ]
        }
        """
        try:
            # 参数验证
            if not entryorder_data:
                raise ValueError("入库单数据不能为空")

            # 验证必需字段
            if "entryOrder" not in entryorder_data:
                raise ValueError("缺少必需参数: entryOrder")

            if "orderLines" not in entryorder_data:
                raise ValueError("缺少必需参数: orderLines")

            entry_order = entryorder_data["entryOrder"]
            order_lines = entryorder_data["orderLines"]

            # 验证入库单基本信息
            required_entry_fields = ["entryOrderCode", "warehouseCode", "orderType"]
            for field in required_entry_fields:
                if field not in entry_order:
                    raise ValueError(f"入库单缺少必需参数: {field}")

            # 验证入库类型
            valid_order_types = ["CGRK", "DBRK", "QTRK", "B2BRK", "SCRK"]
            if entry_order["orderType"] not in valid_order_types:
                raise ValueError(f"无效的入库类型: {entry_order['orderType']}, 有效值: {valid_order_types}")

            # 验证商品明细
            if not order_lines or len(order_lines) == 0:
                raise ValueError("商品明细不能为空")

            for i, line in enumerate(order_lines):
                if "itemCode" not in line:
                    raise ValueError(f"第{i+1}行商品明细缺少必需参数: itemCode")
                if "planQty" not in line:
                    raise ValueError(f"第{i+1}行商品明细缺少必需参数: planQty")

                # 验证库存类型
                if "inventoryType" in line and line["inventoryType"] not in ["ZP", "CC"]:
                    raise ValueError(f"第{i+1}行商品明细无效的库存类型: {line['inventoryType']}, 有效值: ZP, CC")

            # 构建请求参数
            params = {
                "format": "xml",  # 根据文档，使用XML格式
                "method": "WDT_WMS_ENTRYORDER_CREATE",
            }

            # 构建请求体，严格按照文档结构
            body = {
                "entryOrder": entry_order,
                "orderLines": order_lines  # 直接传递数组，让XML生成器处理
            }

            frappe.logger().info(f"WDT调用入库单创建接口: {entry_order.get('entryOrderCode')}")
            return self._request(params, body)

        except Exception as e:
            frappe.logger().error(f"WDT入库单创建接口调用失败: {e}")
            raise WDTAPIException(f"入库单创建接口调用失败: {e}")

    def wdt_wms_returnorder_create(self, returnorder_data):
        """
        退货入库单创建接口 - WDT_WMS_RETURNORDER_CREATE
        方向: ERP→WMS
        严格按照旺店通接口文档实现

        参数结构:
        returnorder_data = {
            "returnOrder": {
                "returnOrderCode": "ERP的退货入库单编码,varchar(50),必填,唯一值",
                "warehouseCode": "仓库编码,varchar(50),必填",
                "orderType": "单据类型(THRK=退货入库;HHRK=换货入库;只传英文编码),tinyint(4),必填",
                "preDeliveryOrderCode": "原出库单号(ERP分配),varchar(50)",
                "logisticsName": "物流公司名称,varchar(64)",
                "expressCode": "运单号,varchar(50)",
                "buyerNick": "买家昵称,varchar(100)",
                "shopNick": "店铺名称,varchar(40)",
                "remark": "备注,varchar(255)",
                "extendProps": "扩展属性,map",
                "senderInfo": {
                    "name": "姓名,varchar(40)",
                    "tel": "固定电话,varchar(32)",
                    "mobile": "移动电话,varchar(30)",
                    "detailAddress": "详细地址,varchar(255)"
                }
            },
            "orderLines": [
                {
                    "orderLineNo": "单据行号单据行号(订单中一个货品有多条记录时必填,保证同一个货品的orderLineNo不同),varchar(50)",
                    "sourceOrderCode": "原订单的交易平台订单,varchar(128)",
                    "itemCode": "商家编码,varchar(50),必填",
                    "itemName": "货品名称,varchar(255)",
                    "inventoryType": "库存类型(ZP=正品;CC=残次;默认为ZP,只传英文编码),tinyint(4)",
                    "planQty": "应收商品数量,decimal(19,4),必填",
                    "batchCode": "批次编码,varchar(50)",
                    "expireDate": "过期日期(YYYY-MM-DD),datetime",
                    "productDate": "生产日期(YYYY-MM-DD),datetime",
                    "remark": "货品备注,varchar(255)"
                }
            ]
        }
        """
        try:
            # 参数验证
            if not returnorder_data:
                raise ValueError("退货入库单数据不能为空")

            # 验证必需字段
            if "returnOrder" not in returnorder_data:
                raise ValueError("缺少必需参数: returnOrder")

            if "orderLines" not in returnorder_data:
                raise ValueError("缺少必需参数: orderLines")

            return_order = returnorder_data["returnOrder"]
            order_lines = returnorder_data["orderLines"]

            # 验证退货入库单基本信息
            required_return_fields = ["returnOrderCode", "warehouseCode", "orderType"]
            for field in required_return_fields:
                if field not in return_order:
                    raise ValueError(f"退货入库单缺少必需参数: {field}")

            # 验证单据类型
            valid_order_types = ["THRK", "HHRK"]
            if return_order["orderType"] not in valid_order_types:
                raise ValueError(f"无效的单据类型: {return_order['orderType']}, 有效值: {valid_order_types}")

            # 验证商品明细
            if not order_lines or len(order_lines) == 0:
                raise ValueError("商品明细不能为空")

            for i, line in enumerate(order_lines):
                if "itemCode" not in line:
                    raise ValueError(f"第{i+1}行商品明细缺少必需参数: itemCode")
                if "planQty" not in line:
                    raise ValueError(f"第{i+1}行商品明细缺少必需参数: planQty")

                # 验证库存类型
                if "inventoryType" in line and line["inventoryType"] not in ["ZP", "CC"]:
                    raise ValueError(f"第{i+1}行商品明细无效的库存类型: {line['inventoryType']}, 有效值: ZP, CC")

            # 构建请求参数
            params = {
                "format": "xml",  # 根据文档，使用XML格式
                "method": "WDT_WMS_RETURNORDER_CREATE",
            }

            # 构建请求体，严格按照文档结构
            body = {
                "returnOrder": return_order,
                "orderLines": order_lines  # 直接传递数组，让XML生成器处理
            }

            frappe.logger().info(f"WDT调用退货入库单创建接口: {return_order.get('returnOrderCode')}")
            return self._request(params, body)

        except Exception as e:
            frappe.logger().error(f"WDT退货入库单创建接口调用失败: {e}")
            raise WDTAPIException(f"退货入库单创建接口调用失败: {e}")

    def wdt_wms_order_cancel(self, cancel_data):
        """
        取消接口 - WDT_WMS_ORDER_CANCEL
        方向: ERP→WMS
        严格按照旺店通接口文档实现

        参数结构:
        cancel_data = {
            "warehouseCode": "仓库编码,varchar(50),必填",
            "orderCode": "单据编码,varchar(50),必填",
            "orderType": "单据类型(JYCK=一般交易出库单;HHCK=换货出库;PTCK=普通出库单;DBCK=调拨出库;B2BCK=B2B出库;QTCK=其他出库;CGTH=采购退货出库单;BFCK=补发出库;SCCK=生产出库;SCRK=生产入库;CGRK=采购入库;DBRK=调拨入库;QTRK=其他入库;THRK=退货入库;HHRK=换货入库;B2BRK=B2B入库,只传英文编码),tinyint(4),必填",
            "cancelReason": "取消原因,varchar(250)"
        }
        """
        try:
            # 参数验证
            if not cancel_data:
                raise ValueError("取消数据不能为空")

            # 验证必需字段
            required_fields = ["warehouseCode", "orderCode", "orderType"]
            for field in required_fields:
                if field not in cancel_data:
                    raise ValueError(f"缺少必需参数: {field}")

            # 验证单据类型
            valid_order_types = [
                "JYCK", "HHCK", "PTCK", "DBCK", "B2BCK", "QTCK", "CGTH",
                "BFCK", "SCCK", "SCRK", "CGRK", "DBRK", "QTRK", "THRK",
                "HHRK", "B2BRK"
            ]
            if cancel_data["orderType"] not in valid_order_types:
                raise ValueError(f"无效的单据类型: {cancel_data['orderType']}, 有效值: {valid_order_types}")

            # 构建请求参数
            params = {
                "format": "xml",  # 根据文档，使用XML格式
                "method": "WDT_WMS_ORDER_CANCEL",
            }

            # 构建请求体，严格按照文档结构
            body = {
                "warehouseCode": cancel_data["warehouseCode"],
                "orderCode": cancel_data["orderCode"],
                "orderType": cancel_data["orderType"],
                "cancelReason": cancel_data.get("cancelReason", "")
            }

            frappe.logger().info(f"WDT调用取消接口: {cancel_data.get('orderCode')}")
            return self._request(params, body)

        except Exception as e:
            frappe.logger().error(f"WDT取消接口调用失败: {e}")
            raise WDTAPIException(f"取消接口调用失败: {e}")

    def wdt_wms_inventory_query(self, query_data):
        """
        库存查询接口(多商品) - WDT_WMS_INVENTORY_QUERY
        方向: ERP→WMS
        严格按照旺店通接口文档实现

        参数结构:
        query_data = {
            "criteriaList": [
                {
                    "warehouseCode": "仓库编码,varchar(50),必填",
                    "ownerCode": "货主编码,varchar(50),必填",
                    "itemCode": "商家编码,varchar(50),必填",
                    "inventoryType": "库存类型(ZP=正品;CC=残次。默认为查所有类型的库存,只传英文编码),tinyint(4)",
                    "remark": "备注,varchar(255)"
                }
            ],
            "remark": "备注,varchar(255)"
        }
        """
        try:
            # 参数验证
            if not query_data:
                raise ValueError("查询参数不能为空")

            # 验证必需字段
            if "criteriaList" not in query_data:
                raise ValueError("缺少必需参数: criteriaList")

            criteria_list = query_data["criteriaList"]
            if not criteria_list or len(criteria_list) == 0:
                raise ValueError("查询条件列表不能为空")

            # 验证每个查询条件
            for i, criteria in enumerate(criteria_list):
                required_criteria_fields = ["warehouseCode", "ownerCode", "itemCode"]
                for field in required_criteria_fields:
                    if field not in criteria:
                        raise ValueError(f"第{i+1}个查询条件缺少必需参数: {field}")

                # 验证库存类型
                if "inventoryType" in criteria and criteria["inventoryType"] not in ["ZP", "CC"]:
                    raise ValueError(f"第{i+1}个查询条件无效的库存类型: {criteria['inventoryType']}, 有效值: ZP, CC")

            # 构建请求参数
            params = {
                "format": "xml",  # 根据文档，使用XML格式
                "method": "WDT_WMS_INVENTORY_QUERY",
            }

            # 构建请求体，严格按照文档结构
            body = {
                "criteriaList": criteria_list,  # 直接传递数组
                "remark": query_data.get("remark", "")
            }

            frappe.logger().error(f"WDT调用库存查询接口: {len(criteria_list)}个查询条件")
            frappe.logger().error(f"请求体数据: {body}")
            return self._request(params, body)

        except Exception as e:
            frappe.logger().error(f"WDT库存查询接口调用失败: {e}")
            raise WDTAPIException(f"库存查询接口调用失败: {e}")



    # ==================== 其他接口实现 ====================

    # ==================== 商品管理接口 ====================

    def wdt_wms_singleitem_synchronize(self, item_data):
        """
        商品同步接口 - WDT_WMS_SINGLEITEM_SYNCHRONIZE
        方向: ERP→WMS
        严格按照旺店通接口文档实现

        参数结构:
        item_data = {
            "actionType": "add|update,必填",
            "warehouseCode": "仓库编码,varchar(50)",
            "item": {
                "itemCode": "商家编码(sid+itemCode一致传add也会识别为update),varchar(50),必填,商品唯一码",
                "goodsCode": "货品编号,varchar(50),注意：actionType字段传update时可不传该字段，若传该字段值不可为空",
                "itemName": "货品名称,varchar(255),必填",
                "shortName": "货品简称,varchar(255)",
                "title": "货品别名,varchar(255)",
                "barCode": "条形码,varchar(100),必填",
                "skuProperty": "规格名称(如红色, XXL),varchar(200)",
                "spec_code": "规格码,varchar(40)",
                "stockUnit": "基本单位,varchar(16)",
                "length": "长(厘米),decimal(19,4)",
                "width": "宽(厘米),decimal(19,4)",
                "height": "高(厘米),decimal(19,4)",
                "volume": "体积(升),decimal(19,4)",
                "grossWeight": "毛重(千克),decimal(19,4)",
                "categoryId": "分类编号,varchar(50)",
                "categoryName": "分类名称,varchar(100)",
                "itemType": "商品类型(ZC=正常商品;BC=包材;只传英文编码),string(50),必填",
                "retailPrice": "价格,decimal(19,4)",
                "brandName": "品牌,string(50)",
                "brandCode": "品牌编号,string(50)",
                "isSNMgmt": "启用序列号,Y/N(默认为N),若为Y看系统配置传入为强序列号或弱序列号,tinyint(4)",
                "shelfLife": "保质期(小时),decimal(19,4)",
                "isBatchMgmt": "是否需要批次管理,Y/N(默认为N),tinyint(4)",
                "pcs": "箱规,decimal(19,4)",
                "originAddress": "商品的原产地,varchar(64)",
                "remark": "备注,varchar(512)",
                "size": "尺寸,varchar(50)",
                "color": "颜色,varchar(50)",
                "auxUnit": "一级单位,varchar(16)",
                "auxUnitRatio": "每包数量,int",
                "adventLifecycle": "临期天数,int",
                "receiveDays": "最佳收货天数,int",
                "extendProps": {
                    "imageUrl": "图片,varchar(1024)",
                    "specprop1": "商品自定义属性1,varchar(255)",
                    "goodsprop1": "货品自定义属性1,varchar(255)",
                    "specprop2": "商品自定义属性2,varchar(255)",
                    "goodsprop2": "货品自定义属性2,varchar(255)",
                    "specprop3": "商品自定义属性3,varchar(255)",
                    "goodsprop3": "货品自定义属性3,varchar(255)",
                    "specprop4": "商品自定义属性4,varchar(255)",
                    "goodsprop4": "货品自定义属性4,varchar(255)",
                    "specprop5": "商品自定义属性5,varchar(255)",
                    "goodsprop5": "货品自定义属性5,varchar(255)",
                    "specprop6": "商品自定义属性6,varchar(255)",
                    "goodsprop6": "货品自定义属性6,varchar(255)",
                    "boxVolume": "箱体积（立方厘米）,decimal(19,4)",
                    "boxWeight": "箱重量（千克）,decimal(19,4)"
                }
            }
        }
        """
        try:
            # 参数验证
            if not item_data:
                raise ValueError("商品数据不能为空")

            # 验证必需字段
            if "actionType" not in item_data:
                raise ValueError("缺少必需参数: actionType")

            if "item" not in item_data:
                raise ValueError("缺少必需参数: item")

            # 验证actionType
            valid_action_types = ["add", "update"]
            if item_data["actionType"] not in valid_action_types:
                raise ValueError(f"无效的操作类型: {item_data['actionType']}, 有效值: {valid_action_types}")

            # 验证商品信息
            item = item_data["item"]
            required_item_fields = ["itemCode", "itemName", "barCode", "itemType"]
            for field in required_item_fields:
                if field not in item:
                    raise ValueError(f"商品信息缺少必需参数: {field}")

            # 验证商品类型
            valid_item_types = ["ZC", "BC"]
            if item["itemType"] not in valid_item_types:
                raise ValueError(f"无效的商品类型: {item['itemType']}, 有效值: {valid_item_types}")

            # 验证序列号管理
            if "isSNMgmt" in item and item["isSNMgmt"] not in ["Y", "N"]:
                raise ValueError(f"无效的序列号管理设置: {item['isSNMgmt']}, 有效值: Y, N")

            # 验证批次管理
            if "isBatchMgmt" in item and item["isBatchMgmt"] not in ["Y", "N"]:
                raise ValueError(f"无效的批次管理设置: {item['isBatchMgmt']}, 有效值: Y, N")

            # 构建请求参数
            params = {
                "format": "xml",  # 根据文档，使用XML格式
                "method": "WDT_WMS_SINGLEITEM_SYNCHRONIZE",
            }

            # 构建请求体，严格按照文档结构
            body = {
                "actionType": item_data["actionType"],
                "warehouseCode": item_data.get("warehouseCode"),
                "item": item
            }

            frappe.logger().info(f"WDT调用商品同步接口: {item.get('itemCode')}")
            return self._request(params, body)

        except Exception as e:
            frappe.logger().error(f"WDT商品同步接口调用失败: {e}")
            frappe.logger().error(f"WDT接口返回信息: {e}")
            return {
                "success": False,
                "error": str(e),
                "message": f"商品同步接口调用失败: {e}"
            }

    def wdt_wms_singleitem_query(self, query_data):
        """
        商品查询接口 - WDT_WMS_SINGLEITEM_QUERY
        方向: ERP→WMS
        严格按照旺店通接口文档实现

        参数结构:
        query_data = {
            "ownerCode": "货主编码,varchar(50)",
            "itemCode": "商家编码,varchar(50),必填"
        }
        """
        try:
            # 参数验证
            if not query_data:
                raise ValueError("查询参数不能为空")

            # 验证必需字段
            if "itemCode" not in query_data:
                raise ValueError("缺少必需参数: itemCode")

            # 构建请求参数
            params = {
                "format": "xml",  # 根据文档，使用XML格式
                "method": "WDT_WMS_SINGLEITEM_QUERY",
            }

            # 构建请求体，严格按照文档结构
            body = {
                "ownerCode": query_data.get("ownerCode"),
                "itemCode": query_data["itemCode"]
            }

            frappe.logger().info(f"WDT调用商品查询接口: {query_data.get('itemCode')}")
            return self._request(params, body)

        except Exception as e:
            frappe.logger().error(f"WDT商品查询接口调用失败: {e}")
            raise WDTAPIException(f"商品查询接口调用失败: {e}")

    # ==================== 出库相关接口 ====================

    def wdt_wms_stockout_create(self, stockout_data):
        """
        出库单创建接口(非销售订单) - WDT_WMS_STOCKOUT_CREATE
        方向: ERP→WMS
        严格按照旺店通接口文档实现

        参数结构:
        stockout_data = {
            "deliveryOrder": {
                "deliveryOrderCode": "出库单号,varchar(50),必填,唯一值",
                "warehouseCode": "仓库编码,varchar(50),必填",
                "createTime": "出库单创建时间(YYYY-MM-DD HH:MM:SS),datetime",
                "orderType": "出库单类型(PTCK=普通出库单;DBCK=调拨出库;B2BCK=B2B出库(唯品出库);QTCK=其他出库;CGTH=采购退货出库单;SCCK=生产出库,只传英文编码),tinyint(4),必填",
                "logisticsCode": "物流公司编码,varchar(50),物流编码在仓库里做映射,接口推送后展示物流名称字段",
                "VpExpressCode": "物流单号,varchar(50)",
                "supplierCode": "供应商编码,varchar(30)",
                "supplierName": "供应商名称,varchar(100)",
                "totalAmount": "订单金额,decimal(19,4)",
                "remark": "备注,varchar(255)",
                "receiverInfo": {
                    "name": "姓名,varchar(40)",
                    "tel": "固定电话,varchar(32)",
                    "mobile": "移动电话,varchar(30)",
                    "province": "省,varchar(50)",
                    "city": "市,varchar(50)",
                    "area": "区,varchar(50)",
                    "receiver_area": "varchar(50)",
                    "detailAddress": "详细地址,varchar(255),字段必传值可为空",
                    "company": "公司,varchar(40)"
                },
                "extendProps": {
                    "VpExpressCode": "物流单号,varchar(50)",
                    "vipWarehouseCode": "到货仓编码,varchar(50)",
                    "VpStockInOrderNO": "唯品会入库单号(orderType=B2BCK时必填),varchar(50)",
                    "VpPackageNO": "唯品会PO号(orderType=B2BCK时必填),varchar(50)",
                    "VpOutTime": "客户端的到货时间,(YYYY-MM-DD HH:MM:SS),datetime",
                    "shipment_type": "自定义属性1,varchar(255)",
                    "platform_code": "自定义属性2,varchar(255)",
                    "prop3_code": "自定义属性3,varchar(255)"
                }
            },
            "orderLines": [
                {
                    "orderLineNo": "单据行号(订单中一个货品有多条记录时必填,保证同一个货品的orderLineNo不同),varchar(50)",
                    "itemCode": "商家编码,varchar(50),必填",
                    "itemId": "商品id,varchar(50)",
                    "itemName": "商品名称,varchar(255)",
                    "inventoryType": "库存类型(ZP=正品;CC=残次;默认为ZP,只传英文编码),tinyint(4)",
                    "batchCode": "批次编码,varchar(50)",
                    "expireDate": "过期日期(YYYY-MM-DD),datetime",
                    "productDate": "生产日期(YYYY-MM-DD),datetime",
                    "planQty": "应发商品数量,decimal(19,4),必填",
                    "remark": "备注,varchar(255)",
                    "actualPrice": "实际成交价,decimal(19,4)",
                    "isGift": "是否赠品,0表示非赠品，1自动赠送，2表示手动赠送"
                }
            ]
        }
        """
        try:
            # 参数验证
            if not stockout_data:
                raise ValueError("出库单数据不能为空")

            # 验证必需字段
            if "deliveryOrder" not in stockout_data:
                raise ValueError("缺少必需参数: deliveryOrder")

            if "orderLines" not in stockout_data:
                raise ValueError("缺少必需参数: orderLines")

            delivery_order = stockout_data["deliveryOrder"]
            order_lines = stockout_data["orderLines"]

            # 验证出库单基本信息
            required_delivery_fields = ["deliveryOrderCode", "warehouseCode", "orderType"]
            for field in required_delivery_fields:
                if field not in delivery_order:
                    raise ValueError(f"出库单缺少必需参数: {field}")

            # 验证出库单类型
            valid_order_types = ["PTCK", "DBCK", "B2BCK", "QTCK", "CGTH", "SCCK"]
            if delivery_order["orderType"] not in valid_order_types:
                raise ValueError(f"无效的出库单类型: {delivery_order['orderType']}, 有效值: {valid_order_types}")

            # 验证商品明细
            if not order_lines or len(order_lines) == 0:
                raise ValueError("商品明细不能为空")

            for i, line in enumerate(order_lines):
                if "itemCode" not in line:
                    raise ValueError(f"第{i+1}行商品明细缺少必需参数: itemCode")
                if "planQty" not in line:
                    raise ValueError(f"第{i+1}行商品明细缺少必需参数: planQty")

                # 验证库存类型
                if "inventoryType" in line and line["inventoryType"] not in ["ZP", "CC"]:
                    raise ValueError(f"第{i+1}行商品明细无效的库存类型: {line['inventoryType']}, 有效值: ZP, CC")

                # 验证赠品标识
                if "isGift" in line and line["isGift"] not in [0, 1, 2]:
                    raise ValueError(f"第{i+1}行商品明细无效的赠品标识: {line['isGift']}, 有效值: 0, 1, 2")

            # 构建请求参数
            params = {
                "format": "xml",  # 根据文档，使用XML格式
                "method": "WDT_WMS_STOCKOUT_CREATE",
            }

            # 构建请求体，严格按照文档结构
            body = {
                "deliveryOrder": delivery_order,
                "orderLines": order_lines  # 直接传递数组，让XML生成器处理
            }

            frappe.logger().info(f"WDT调用出库单创建接口: {delivery_order.get('deliveryOrderCode')}")
            return self._request(params, body)

        except Exception as e:
            frappe.logger().error(f"WDT出库单创建接口调用失败: {e}")
            raise WDTAPIException(f"出库单创建接口调用失败: {e}")

    def wdt_wms_deliveryorder_create(self, delivery_data):
        """
        发货单创建接口(销售订单) - WDT_WMS_DELIVERYORDER_CREATE
        方向: ERP→WMS
        严格按照旺店通接口文档实现

        参数结构:
        delivery_data = {
            "deliveryOrder": {
                "deliveryOrderCode": "出库单号,varchar(50),必填,唯一值",
                "preDeliveryOrderCode": "原出库单号(ERP分配),varchar(50)",
                "orderType": "出库单类型(JYCK=一般交易出库单;HHCK=换货出库单;BFCK=补发出库单,只传英文编码),tinyint(4),必填",
                "warehouseCode": "仓库编码,varchar(50),必填",
                "orderFlag": "货到付款订单，可以使用的枚举值如下：COD=货到付款，只需要传递编码,非必填，varchar(50)",
                "sourcePlatformCode": "订单来源平台编码(TB=淘宝;TMGJ=天猫国际;TM=天猫;JD=京东;PP=拍拍;AMAZON=亚马逊;YHD=1号店;DD=当当;GM=国美;PDD=拼多多;PDDDF=拼多多代发（代发业务，用buyerNick传递代打店铺ID）;VANCL=凡客;SN=苏宁;WPH=唯品会;YX=易讯;JM=聚美;MGJ=蘑菇街;WPH_JITX=唯品会的JITX;YJ=云集;YZ=有赞;TMCS=天猫超市;DYXD=抖店;KS=快手小店;ZYPT=自有平台;MT=美团;HWSC=华为商城;DWZF=得物直发;DYGX=抖音供销;WXSPHXD=微信视频号;OTHER=其他,只传英文编码),tinyint(4)",
                "sourcePlatformName": "订单来源平台名称,varchar(50)",
                "createTime": "发货单创建时间(YYYY-MM-DD HH:MM:SS),datetime,必填",
                "placeOrderTime": "前台订单/店铺订单的创建时间/下单时间(YYYY-MM-DD HH:MM:SS),datetime,必填",
                "payTime": "订单支付时间(YYYY-MM-DD HH:MM:SS),datetime",
                "payNo": "支付平台交易号,varchar(50)",
                "operateTime": "操作(审核)时间(YYYY-MM-DD HH:MM:SS),datetime,必填",
                "shopNick": "店铺名称,varchar(40)",
                "buyerNick": "买家昵称（当sourcePlatformCode=PDDDF时，表示拼多多代发业务，传递代打店铺ID）,varchar(100)",
                "totalAmount": "订单总金额(订单总金额=应收金额+已收金额=商品总金额-订单折扣金额+快递费用;单位元),decimal(19,4)",
                "itemAmount": "商品总金额(元),decimal(19,4)",
                "discountAmount": "订单折扣金额(元),decimal(19,4)",
                "freight": "快递费用(元),decimal(18,2)",
                "arAmount": "应收金额,decimal(18,2)",
                "gotAmount": "已收金额(消费者已经支付多少;单位元),decimal(18,2)",
                "serviceFee": "COD服务费,decimal(18,2)",
                "logisticsCode": "物流公司编码(对应wms仓库物流映射的"oms物流编码"),varchar(50),必填",
                "logisticsName": "物流公司名称,varchar(64)",
                "expressCode": "运单号,varchar(50)",
                "logisticsAreaCode": "快递区域编码/大头笔/三段码,varchar(128)",
                "invoiceFlag": "是否需要发票,Y/N(默认为N),tinyint(4)",
                "deliveryRequirements": {
                    "scheduleType": "投递时延要求(1=工作日;2=节假日;101=当日达;102=次晨达;103=次日达;104=预约达;105=隔日达,只传数字编码),smallint(6)",
                    "scheduleDay": "要求送达日期(YYYY-MM-DD),datetime",
                    "deliveryType": "发货服务类型(PTPS:普通配送;LLPS:冷链配送;HBP:环保配),string(50)",
                    "scheduleStartTime": "投递时间范围要求(开始时间;格式：HH:MM:SS),datetime",
                    "scheduleEndTime": "投递时间范围要求(结束时间;格式：HH:MM:SS),datetime"
                },
                "senderInfo": {
                    "company": "公司名称,varchar(200)",
                    "name": "姓名,varchar(50)",
                    "zipCode": "邮编,varchar(20)",
                    "tel": "固定电话,varchar(40)",
                    "mobile": "移动电话,varchar(40)",
                    "email": "电子邮箱,varchar(50)",
                    "countryCode": "国家二字码,varchar(4)",
                    "province": "省份,varchar(50)",
                    "city": "城市,varchar(50)",
                    "area": "区域,varchar(50)",
                    "detailAddress": "详细地址,varchar(255)"
                },
                "receiverInfo": {
                    "name": "姓名,varchar(50),必填",
                    "zipCode": "邮编,varchar(40)",
                    "tel": "固定电话,varchar(40)",
                    "mobile": "移动电话,varchar(40),必填",
                    "idType": "收件人证件类型(1=身份证;2=军官证;3=护照;4=其他),tinyint(4)",
                    "idNumber": "收件人证件号码,varchar(40)",
                    "countryCode": "收件人国家二字码,varchar(4)",
                    "province": "省份,varchar(50),必填",
                    "city": "城市,varchar(50),必填",
                    "area": "区域,varchar(50)",
                    "town": "乡镇,varchar(50)",
                    "detailAddress": "详细地址,varchar(255),必填",
                    "oaid": "淘系订单收件人oaid,varchar(50)"
                },
                "invoices": [
                    {
                        "type": "发票类型(INVOICE=普通发票;VINVOICE=增值税普通发票;EVINVOICE=电子增票;invoiceFlag=Y时必填),varchar(50)",
                        "header": "发票抬头,varchar(255)",
                        "content": "发票内容,varchar(255)",
                        "amount": "发票总金额,decimal(18,2)"
                    }
                ],
                "buyerMessage": "买家留言,varchar(1024)",
                "sellerMessage": "卖家留言,varchar(1024)",
                "printRemark": "打印备注,varchar(255)",
                "remark": "单据备注,varchar(255)",
                "extendProps": {
                    "foreignTrade": "是否为跨境订单，传Y则识别为跨境订单，非必填",
                    "expressPDF": "若是跨境订单则传递面单PDF，非必填"
                }
            },
            "orderLines": [
                {
                    "orderLineNo": "单据行号(订单中一个货品有多条记录时必填,保证同一个货品的orderLineNo不同),varchar(50)",
                    "sourceOrderCode": "交易平台订单,varchar(128)",
                    "subSourceOrderCode": "交易平台子订单编码,varchar(128)",
                    "itemCode": "商家编码,varchar(50),必填",
                    "itemName": "商品名称,varchar(255)",
                    "inventoryType": "库存类型(ZP=正品,只传英文编码),tinyint(4)",
                    "planQty": "应发商品数量,decimal(19,4),必填",
                    "retailPrice": "零售价(零售价=实际成交价+单件商品折扣金额),decimal(19,4)",
                    "actualPrice": "实际成交价,decimal(18,2)",
                    "discountAmount": "单件商品折扣金额,decimal(19,4)",
                    "batchCode": "批次编码,varchar(50)",
                    "remark": "货品备注,varchar(255)",
                    "extendProps": {
                        "isGift": "是否赠品,0=非赠品,1=赠品,2=手动赠送"
                    }
                }
            ],
            "extendProps": {
                "ConsolidationCode": "集包地编码,varchar(10)",
                "ConsolidationName": "集包地名称,varchar(40)",
                "printData": "组件加密信息,varchar(8192)",
                "Position": "位置,varchar(30)",
                "SenderAdr": "发货网点,varchar(50)",
                "QrCode": "二维码,varchar(255)",
                "PositionNo": "位置编号,varchar(50)",
                "OriginalCode": "源地址编号,varchar(50)",
                "PostidCode": "组合物流单号,varchar(40)",
                "DestinationCode": "目的地,varchar(50)",
                "PrintInfo": "水印,varchar(256)",
                "businessModel": "sourcePlatformCode=TMGJZY/TMGJ,传1/2,varchar(50)",
                "supplierId": "供应商id,varchar(50)"
            }
        }
        """
        try:
            # 参数验证
            if not delivery_data:
                raise ValueError("发货单数据不能为空")

            # 验证必需字段
            if "deliveryOrder" not in delivery_data:
                raise ValueError("缺少必需参数: deliveryOrder")

            if "orderLines" not in delivery_data:
                raise ValueError("缺少必需参数: orderLines")

            delivery_order = delivery_data["deliveryOrder"]
            order_lines = delivery_data["orderLines"]

            # 验证发货单基本信息
            required_delivery_fields = ["deliveryOrderCode", "orderType", "warehouseCode", "createTime", "placeOrderTime", "operateTime", "logisticsCode"]
            for field in required_delivery_fields:
                if field not in delivery_order:
                    raise ValueError(f"发货单缺少必需参数: {field}")

            # 验证出库单类型
            valid_order_types = ["JYCK", "HHCK", "BFCK"]
            if delivery_order["orderType"] not in valid_order_types:
                raise ValueError(f"无效的发货单类型: {delivery_order['orderType']}, 有效值: {valid_order_types}")

            # 验证货到付款标识
            if "orderFlag" in delivery_order and delivery_order["orderFlag"] not in ["COD"]:
                raise ValueError(f"无效的货到付款标识: {delivery_order['orderFlag']}, 有效值: COD")

            # 验证发票标识
            if "invoiceFlag" in delivery_order and delivery_order["invoiceFlag"] not in ["Y", "N"]:
                raise ValueError(f"无效的发票标识: {delivery_order['invoiceFlag']}, 有效值: Y, N")

            # 验证收件人信息
            if "receiverInfo" in delivery_order:
                receiver_info = delivery_order["receiverInfo"]
                required_receiver_fields = ["name", "mobile", "province", "city", "detailAddress"]
                for field in required_receiver_fields:
                    if field not in receiver_info:
                        raise ValueError(f"收件人信息缺少必需参数: {field}")

            # 验证商品明细
            if not order_lines or len(order_lines) == 0:
                raise ValueError("商品明细不能为空")

            for i, line in enumerate(order_lines):
                if "itemCode" not in line:
                    raise ValueError(f"第{i+1}行商品明细缺少必需参数: itemCode")
                if "planQty" not in line:
                    raise ValueError(f"第{i+1}行商品明细缺少必需参数: planQty")

                # 验证库存类型
                if "inventoryType" in line and line["inventoryType"] not in ["ZP"]:
                    raise ValueError(f"第{i+1}行商品明细无效的库存类型: {line['inventoryType']}, 有效值: ZP")

                # 验证赠品标识
                if "extendProps" in line and "isGift" in line["extendProps"]:
                    if line["extendProps"]["isGift"] not in [0, 1, 2]:
                        raise ValueError(f"第{i+1}行商品明细无效的赠品标识: {line['extendProps']['isGift']}, 有效值: 0, 1, 2")

            # 构建请求参数
            params = {
                "format": "xml",  # 根据文档，使用XML格式
                "method": "WDT_WMS_DELIVERYORDER_CREATE",
            }

            # 构建请求体，严格按照文档结构
            body = {
                "deliveryOrder": delivery_order,
                "orderLines": order_lines,  # 直接传递数组，让XML生成器处理
                "extendProps": delivery_data.get("extendProps", {})
            }

            frappe.logger().info(f"WDT调用发货单创建接口: {delivery_order.get('deliveryOrderCode')}")
            return self._request(params, body)

        except Exception as e:
            frappe.logger().error(f"WDT发货单创建接口调用失败: {e}")
            raise WDTAPIException(f"发货单创建接口调用失败: {e}")

    def wdt_wms_deliveryorder_confirm(self, confirm_data):
        """
        发货单确认接口 - WDT_WMS_DELIVERYORDER_CONFIRM
        方向: WMS→ERP
        严格按照旺店通接口文档实现

        参数结构:
        confirm_data = {
            "deliveryOrder": {
                "deliveryOrderCode": "出库单号,varchar(50),必填,唯一值",
                "deliveryOrderId": "仓储系统订单号,varchar(50),必填",
                "warehouseCode": "仓库编码,varchar(50),必填",
                "orderType": "出库单类型(JYCK=一般交易出库;HHCK=换货出库;BFCK=补发出库,只传英文编码),tinyint(4),必填",
                "orderConfirmTime": "订单完成时间(YYYY-MM-DD HH:MM:SS),datetime(50),必填",
                "outBizCode": "外部业务编码(消息ID,用于去重,ISV对于同一请求分配一个唯一性的编码,用来保证因为网络等原因导致重复传输,请求不会被重复处理),varchar(50),必填",
                "extendProps": {
                    "logistics_flag": "扩展字段：表示WMS预回传物流。1:预回传物流（该功能需要WMS配置后，配置后才回传该字段）；2:发货后修改物流再回传（对接ERP支持则能回传）。"
                }
            },
            "packages": [
                {
                    "logisticsCode": "物流公司编码,varchar(50),必填",
                    "expressCode": "运单号,varchar(50),必填",
                    "packageCode": "包裹编号,varchar(50)",
                    "weight": "包裹重量(单位:千克),decimal(19,4)",
                    "extendProps": {
                        "postage": "邮费，decimal(19,4)"
                    },
                    "items": [
                        {
                            "itemCode": "商家编码,varchar(50),必填",
                            "quantity": "包裹内该商品的数量,decimal(19,4),必填"
                        }
                    ],
                    "packageMaterialList": [
                        {
                            "type": "包材型号,varchar(50)",
                            "quantity": "包材的数量,decimal(19,4)"
                        }
                    ]
                }
            ],
            "orderLines": [
                {
                    "itemCode": "商家编码,varchar(50),必填",
                    "inventoryType": "库存类型(ZP=正品,只传英文编码),tinyint(4)",
                    "actualQty": "实发商品数量,decimal(19,4)",
                    "orderLineNo": "单据行号,varchar(50)",
                    "remark": "货品备注,varchar(255)",
                    "snList": [
                        {
                            "sn": "sn码信息,varchar(80)"
                        }
                    ],
                    "batchs": [
                        {
                            "batchCode": "批次编号,varchar(50)",
                            "expireDate": "过期日期(YYYY-MM-DD HH:MM:SS),datetime",
                            "productDate": "生产日期(YYYY-MM-DD HH:MM:SS),datetime",
                            "productionDate": "生产日期——历史原因仍然保留老字段忽略即可(YYYY-MM-DD HH:MM:SS),datetime",
                            "actualQty": "实发数量(要求batchs节点下所有的实发数量之和等于orderline中的实发数量),decimal(19,4)",
                            "inventoryType": "库存类型(ZP=正品,只传英文编码),tinyint(4)"
                        }
                    ]
                }
            ]
        }
        """
        try:
            # 参数验证
            if not confirm_data:
                raise ValueError("确认数据不能为空")

            # 验证必需字段
            if "deliveryOrder" not in confirm_data:
                raise ValueError("缺少必需参数: deliveryOrder")

            if "orderLines" not in confirm_data:
                raise ValueError("缺少必需参数: orderLines")

            delivery_order = confirm_data["deliveryOrder"]
            order_lines = confirm_data["orderLines"]

            # 验证发货单基本信息
            required_delivery_fields = ["deliveryOrderCode", "deliveryOrderId", "warehouseCode", "orderType", "orderConfirmTime", "outBizCode"]
            for field in required_delivery_fields:
                if field not in delivery_order:
                    raise ValueError(f"发货单缺少必需参数: {field}")

            # 验证出库单类型
            valid_order_types = ["JYCK", "HHCK", "BFCK"]
            if delivery_order["orderType"] not in valid_order_types:
                raise ValueError(f"无效的发货单类型: {delivery_order['orderType']}, 有效值: {valid_order_types}")

            # 验证商品明细
            if not order_lines or len(order_lines) == 0:
                raise ValueError("商品明细不能为空")

            for i, line in enumerate(order_lines):
                if "itemCode" not in line:
                    raise ValueError(f"第{i+1}行商品明细缺少必需参数: itemCode")

                # 验证库存类型
                if "inventoryType" in line and line["inventoryType"] not in ["ZP"]:
                    raise ValueError(f"第{i+1}行商品明细无效的库存类型: {line['inventoryType']}, 有效值: ZP")

            # 构建请求参数
            params = {
                "format": "xml",  # 根据文档，使用XML格式
                "method": "WDT_WMS_DELIVERYORDER_CONFIRM",
            }

            # 构建请求体，严格按照文档结构
            body = {
                "deliveryOrder": delivery_order,
                "packages": confirm_data.get("packages", []),
                "orderLines": order_lines  # 直接传递数组，让XML生成器处理
            }

            frappe.logger().info(f"WDT调用发货单确认接口: {delivery_order.get('deliveryOrderCode')}")
            self._request(params, body)
            return {
                    "success": True,
                    "flag": "success",
                    "code": "0",
                    "message": "发货单确认已接收"
            }

        except Exception as e:
                frappe.logger().error(f"WDT发货单确认接口处理失败: {e}")
                frappe.log_error(f"WDT发货单确认处理异常", str(e))
                # 不向旺店通返回失败，避免重复推送
                return {
                    "success": False,
                    "flag": "success",
                    "code": "0",
                    "message": "回调已接收，处理异常已记录"
                }

    # ==================== 库存管理接口 ====================

    def wdt_wms_inventory_report(self, report_data):
        """
        盘点单通知接口 - WDT_WMS_INVENTORY_REPORT
        方向: WMS→ERP
        严格按照旺店通接口文档实现

        参数结构:
        report_data = {
            "totalPage": "总页数,number,必填",
            "currentPage": "当前页(从1开始),number,必填",
            "pageSize": "每页记录的条数,number,必填",
            "warehouseCode": "仓库编码,varchar(50),必填",
            "checkOrderCode": "盘点单编码,varchar(50),必填",
            "checkOrderId": "仓储系统的盘点单编码,varchar(50)",
            "pdType": "盘点方案(0=部分盘点;1=全部盘点;2=货位盘点;3=单品盘点;4=异常货位盘点,只传数字编码),tinyint(4)",
            "ownerCode": "货主编码,varchar(50),必填",
            "checkTime": "盘点时间(YYYY-MM-DD HH:MM:SS),datetime",
            "outBizCode": "外部业务编码(消息ID,用于去重,ISV对于同一请求分配一个唯一性的编码,用来保证因为网络等原因导致重复传输,请求不会被重复处理),tinyint(4),必填",
            "remark": "备注,varchar(255)",
            "items": [
                {
                    "itemCode": "商家编码,varchar(50),必填",
                    "inventoryType": "库存类型(ZP=正品;CC=残次),tinyint(4)",
                    "quantity": "盘盈盘亏商品变化量(盘盈为正数;盘亏为负数),decimal(19,4),必填",
                    "batchCode": "批次编码,varchar(50)",
                    "expireDate": "商品过期日期(YYYY-MM-DD HH:MM:SS),datetime",
                    "remark": "备注,varchar(255)",
                    "newNum": "实际盘点量,decimal(19,4)"
                }
            ]
        }
        """
        try:
            # 参数验证
            if not report_data:
                raise ValueError("盘点数据不能为空")

            # 验证必需字段
            required_fields = ["totalPage", "currentPage", "pageSize", "warehouseCode", "checkOrderCode", "ownerCode", "outBizCode"]
            for field in required_fields:
                if field not in report_data:
                    raise ValueError(f"缺少必需参数: {field}")

            # 验证商品明细
            if "items" not in report_data or not report_data["items"]:
                raise ValueError("商品明细不能为空")

            for i, item in enumerate(report_data["items"]):
                if "itemCode" not in item:
                    raise ValueError(f"第{i+1}个商品明细缺少必需参数: itemCode")
                if "quantity" not in item:
                    raise ValueError(f"第{i+1}个商品明细缺少必需参数: quantity")

                # 验证库存类型
                if "inventoryType" in item and item["inventoryType"] not in ["ZP", "CC"]:
                    raise ValueError(f"第{i+1}个商品明细无效的库存类型: {item['inventoryType']}, 有效值: ZP, CC")

            # 构建请求参数
            params = {
                "format": "xml",  # 根据文档，使用XML格式
                "method": "WDT_WMS_INVENTORY_REPORT",
            }

            # 构建请求体，严格按照文档结构
            body = {
                "totalPage": report_data["totalPage"],
                "currentPage": report_data["currentPage"],
                "pageSize": report_data["pageSize"],
                "warehouseCode": report_data["warehouseCode"],
                "checkOrderCode": report_data["checkOrderCode"],
                "ownerCode": report_data["ownerCode"],
                "outBizCode": report_data["outBizCode"]
            }

            # 添加可选字段
            if "checkOrderId" in report_data:
                body["checkOrderId"] = report_data["checkOrderId"]
            if "pdType" in report_data:
                body["pdType"] = report_data["pdType"]
            if "checkTime" in report_data:
                body["checkTime"] = report_data["checkTime"]
            if "remark" in report_data:
                body["remark"] = report_data["remark"]

            # 添加商品明细
            body["items"] = {
                "item": report_data["items"]
            }

            frappe.logger().info(f"WDT调用盘点单通知接口: {report_data.get('checkOrderCode')}")
            return self._request(params, body)

        except Exception as e:
            frappe.logger().error(f"WDT盘点单通知接口调用失败: {e}")
            raise WDTAPIException(f"盘点单通知接口调用失败: {e}")

    def wdt_wms_stockchange_report(self, change_data):
        """
        库存异动通知接口 - WDT_WMS_STOCKCHANGE_REPORT
        方向: WMS→ERP
        严格按照旺店通接口文档实现

        参数结构:
        change_data = {
            "items": [
                {
                    "ownerCode": "货主编码,varchar(50),必填",
                    "warehouseCode": "仓库编码,varchar(50),必填",
                    "orderCode": "引起异动的单据编码,varchar(20),必填",
                    "srcOrderNo": "引起异动的单据仓储单号,varchar(50)",
                    "orderType": "单据类型(THYRK=智能退货入库;未知出入库/WMS开的调拨单/借调单/生产单=QTRK/QTCK,只传英文编码),tinyint(4)",
                    "outBizCode": "外部业务编码(消息ID,用于去重,ISV对于同一请求分配一个唯一性的编码,用来保证因为网络等原因导致重复传输,请求不会被重复处理),tinyint(4),必填",
                    "remark": "备注信息,varchar(255)",
                    "itemCode": "商家编码,varchar(50),必填",
                    "inventoryType": "库存类型(ZP=正品;CC=残次,只传英文编码),tinyint(4)",
                    "quantity": "商品变化数量(可正可负,默认全为正数),decimal(19,4),必填",
                    "changeTime": "异动时间(YYYY-MM-DD HH:MM:SS),datetime",
                    "goodsNo": "货品编号,varchar(50),必填",
                    "batchs": [
                        {
                            "batchCode": "批次编码,varchar(50)",
                            "productDate": "商品生产日期(YYYY-MM-DD HH:MM:SS),datetime",
                            "expireDate": "商品过期日期(YYYY-MM-DD HH:MM:SS),datetime",
                            "quantity": "异动数量,decimal(19,4)",
                            "inventoryType": "库存类型(ZP=正品;CC=残次,只传英文编码),tinyint(4)",
                            "extendProps": {
                                "goods_remark": "货品备注,varchar(255)"
                            }
                        }
                    ]
                }
            ],
            "extendProps": {
                "expressCode": "物流单号(orderType=THYRK时返回),varchar(40)",
                "logisticsCode": "物流公司编码(orderType=THYRK时返回),varchar(50)",
                "logisticsName": "物流公司名字(orderType=THYRK时返回,varchar(64)",
                "buyerNick": "买家网名(orderType=THYRK时返回),varchar(100)",
                "senderName": "发货人名字(orderType=THYRK时返回),varchar(40)",
                "senderMobile": "发货人电话(orderType=THYRK时返回),varchar(30)",
                "src_order_type": "WMS开的借调单返回,varchar(40)",
                "wdtwms_src_order_no": "WMS开的借调单返回,varchar(40)",
                "wdtwms_in_owner_no": "WMS开的借调单返回,varchar(40)",
                "wdtwms_in_warehouse_no": "WMS开的借调单返回,varchar(40)",
                "isWdtWmsType": "WMS类型,varchar(40)",
                "process_num": "实际生产次数（不回传默认为1）,int(11)",
                "process_amount": "生产实际费用,decimal(19,4)",
                "srcOrderNo": "WMS开的库存操作业务单返回,varchar(40)"
            }
        }
        """
        try:
            # 参数验证
            if not change_data:
                raise ValueError("异动数据不能为空")

            # 验证必需字段
            if "items" not in change_data or not change_data["items"]:
                raise ValueError("商品明细不能为空")

            # 验证每个商品明细
            for i, item in enumerate(change_data["items"]):
                required_item_fields = ["ownerCode", "warehouseCode", "orderCode", "outBizCode", "itemCode", "quantity", "changeTime", "goodsNo"]
                for field in required_item_fields:
                    if field not in item:
                        raise ValueError(f"第{i+1}个商品明细缺少必需参数: {field}")

                # 验证库存类型
                if "inventoryType" in item and item["inventoryType"] not in ["ZP", "CC"]:
                    raise ValueError(f"第{i+1}个商品明细无效的库存类型: {item['inventoryType']}, 有效值: ZP, CC")

                # 验证单据类型
                if "orderType" in item and item["orderType"] not in ["THYRK", "QTRK", "QTCK"]:
                    raise ValueError(f"第{i+1}个商品明细无效的单据类型: {item['orderType']}, 有效值: THYRK, QTRK, QTCK")

            # 构建请求参数
            params = {
                "format": "xml",  # 根据文档，使用XML格式
                "method": "WDT_WMS_STOCKCHANGE_REPORT",
            }

            # 构建请求体，严格按照文档结构
            body = {
                "items": {
                    "item": change_data["items"]
                }
            }

            # 添加扩展属性
            if "extendProps" in change_data:
                body["extendProps"] = change_data["extendProps"]

            frappe.logger().info(f"WDT调用库存异动通知接口: {len(change_data['items'])}个商品")
            return self._request(params, body)

        except Exception as e:
            frappe.logger().error(f"WDT库存异动通知接口调用失败: {e}")
            raise WDTAPIException(f"库存异动通知接口调用失败: {e}")

    # ==================== 订单管理接口 ====================

    def wdt_wms_order_pending(self, pending_data):
        """
        单据挂起接口 - WDT_WMS_ORDER_PENDING
        方向: ERP→WMS
        严格按照旺店通接口文档实现

        参数结构:
        pending_data = {
            "actionType": "操作类型:pending=挂起,varchar(50),必填",
            "warehouseCode": "仓库编码,varchar(50),必填",
            "orderCode": "单据编码,varchar(50),必填",
            "orderType": "单据类型(CGTH=采购退货出库单;PTCK=普通出库单;DBCK=调拨出库;B2BCK=B2B出库;QTCK=其他出库;SCCK=生产出库;B2BRK=B2B入库;SCRK=生产入库;CGRK=采购入库;DBRK=调拨入库;QTRK=其他入库;XTRK=销退入库;THRK=退货入库;HHRK=换货入库;CGTH=采购退货出库单,只传英文编码),tinyint(4),必填",
            "reason": "挂起原因,varchar(250)"
        }
        """
        try:
            # 参数验证
            if not pending_data:
                raise ValueError("挂起数据不能为空")

            # 验证必需字段
            required_fields = ["actionType", "warehouseCode", "orderCode", "orderType"]
            for field in required_fields:
                if field not in pending_data:
                    raise ValueError(f"缺少必需参数: {field}")

            # 验证操作类型
            if pending_data["actionType"] != "pending":
                raise ValueError(f"无效的操作类型: {pending_data['actionType']}, 有效值: pending")

            # 验证单据类型
            valid_order_types = [
                "CGTH", "PTCK", "DBCK", "B2BCK", "QTCK", "SCCK",
                "B2BRK", "SCRK", "CGRK", "DBRK", "QTRK", "XTRK",
                "THRK", "HHRK"
            ]
            if pending_data["orderType"] not in valid_order_types:
                raise ValueError(f"无效的单据类型: {pending_data['orderType']}, 有效值: {valid_order_types}")

            # 构建请求参数
            params = {
                "format": "xml",  # 根据文档，使用XML格式
                "method": "WDT_WMS_ORDER_PENDING",
            }

            # 构建请求体，严格按照文档结构
            body = {
                "actionType": pending_data["actionType"],
                "warehouseCode": pending_data["warehouseCode"],
                "orderCode": pending_data["orderCode"],
                "orderType": pending_data["orderType"],
                "reason": pending_data.get("reason", "")
            }

            frappe.logger().info(f"WDT调用单据挂起接口: {pending_data.get('orderCode')}")
            return self._request(params, body)

        except Exception as e:
            frappe.logger().error(f"WDT单据挂起接口调用失败: {e}")
            raise WDTAPIException(f"单据挂起接口调用失败: {e}")

    def wdt_wms_order_process_query(self, query_data):
        """
        单据流水查询接口 - WDT_WMS_ORDER_PROCESS_QUERY
        方向: ERP→WMS
        严格按照旺店通接口文档实现

        参数结构:
        query_data = {
            "warehouseCode": "仓库编码,varchar(50),必填",
            "orderCode": "单据编码,varchar(50),必填",
            "orderType": "单据类型,JYCK=一般交易出库单,tinyint(4),必填"
        }
        """
        try:
            # 参数验证
            if not query_data:
                raise ValueError("查询参数不能为空")

            # 验证必需字段
            required_fields = ["warehouseCode", "orderCode", "orderType"]
            for field in required_fields:
                if field not in query_data:
                    raise ValueError(f"缺少必需参数: {field}")

            # 验证单据类型
            valid_order_types = ["JYCK"]
            if query_data["orderType"] not in valid_order_types:
                raise ValueError(f"无效的单据类型: {query_data['orderType']}, 有效值: {valid_order_types}")

            # 构建请求参数
            params = {
                "format": "xml",  # 根据文档，使用XML格式
                "method": "WDT_WMS_ORDER_PROCESS_QUERY",
            }

            # 构建请求体，严格按照文档结构
            body = {
                "warehouseCode": query_data["warehouseCode"],
                "orderCode": query_data["orderCode"],
                "orderType": query_data["orderType"]
            }

            frappe.logger().info(f"WDT调用单据流水查询接口: {query_data.get('orderCode')}")
            return self._request(params, body)

        except Exception as e:
            frappe.logger().error(f"WDT单据流水查询接口调用失败: {e}")
            raise WDTAPIException(f"单据流水查询接口调用失败: {e}")

    def stock_total_query(self, owner_no, warehouse_no, is_position=0, defect=None, page_size=10, page_no=0):
        """
        库存总量查询接口 - stock.total.query (定制接口)
        方向: ERP→WMS
        严格按照旺店通定制接口文档实现
        时间跨度：每日 00:00:00 ~ 06:00:59, 12:00:00 ~ 12:30:59, 23:00:00 ~ 23:59:59允许调用接口

        参数:
        owner_no (str): 货主编码,必填
        warehouse_no (str): 仓库编码,必填
        is_position (int, optional): 是否需要返回货位信息(1:是,0:否,默认0)
        defect (int, optional): 正残(0表示正品,1表示残品,不传则查询全部)
        page_size (int, optional): 每页记录的条数(默认10,最大100)
        page_no (int, optional): 页号(从0页开始,默认为0)

        返回结构:
        {
            "flag": "success|failure",
            "code": "错误代码",
            "message": "错误信息",
            "total": "数据的总条数(仅第一页返回)",
            "content": [
                {
                    "warehouse_no": "仓库编码",
                    "spec_no": "货品商家编码",
                    "spec_name": "货品规格名称",
                    "goods_name": "货品名字",
                    "defect": "正残(0表示正品,1表示残品)",
                    "quantity": "库存数量",
                    "sending_num": "待发货量",
                    "order_num": "待审核量",
                    "available_num": "可发库存",
                    "batch_no": "批次编码",
                    "product_date": "商品生产日期",
                    "expire_date": "商品过期日期",
                    "position_no": "货位编号(is_position=1时返回)",
                    "zone_type": "货区类型(is_position=1时返回,1:暂存区,2:拣货区,3:备货区,4:残品区,0:其它区)"
                }
            ]
        }
        """
        try:
            # 参数验证
            if not owner_no:
                raise ValueError("货主编码不能为空")

            if not warehouse_no:
                raise ValueError("仓库编码不能为空")

            # 验证可选参数
            if is_position not in [0, 1]:
                raise ValueError("is_position参数值无效，有效值: 0(否), 1(是)")

            if defect is not None and defect not in [0, 1]:
                raise ValueError("defect参数值无效，有效值: 0(正品), 1(残品)")

            if page_size < 1 or page_size > 100:
                raise ValueError("page_size参数值无效，有效范围: 1-100")

            if page_no < 0:
                raise ValueError("page_no参数值无效，必须大于等于0")
                
            custom_host = "http://123.56.134.23/open_api/service.php"
            custom_appkey = "commonAppkey"
            custom_appsecret = "commonSecret"
            custom_sid = "wms_lt2"

            # 旺店通定制接口龙琪仓正式环境
            custom_host = "https://openapi.wdtwms.com/open_api/service.php"
            custom_appkey = "longqi_flowa_wdt"
            custom_appsecret = "330f6c49b06b457ebea814f5338e2ffa"
            custom_sid = "longqi"            


            # 构建请求参数 - 使用JSON格式，按照定制接口文档要求
            params = {
                "format": "json",
                "method": "stock.total.query",
                "appkey": custom_appkey,
                "sign_method": "md5",
                "timestamp": time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()),
                "sid": custom_sid
            }

            # 构建请求体，严格按照文档结构
            body = {
                "owner_no": owner_no,
                "warehouse_no": warehouse_no,
                "is_position": is_position,
                "page_size": page_size,
                "page_no": page_no
            }

            # 添加可选参数
            if defect is not None:
                body["defect"] = defect

            # 生成签名 - 按照旺店通定制接口文档要求
            # 第一步：将公共参数的字段名字按字典序从小到大排序
            sorted_params = sorted(params.items())

            # 第二步：拼接排序后的公共参数的 key、value
            sign_str = ""
            for key, value in sorted_params:
                if key != "sign" and value != "":
                    sign_str += key
                    sign_str += str(value)

            # 第三步：在第二步的结果后面拼接请求体
            body_json = json.dumps(body, ensure_ascii=False)
            sign_str += body_json

            # 第四步：在第三步的结果的首尾拼接 appsecret
            sign_str = custom_appsecret + sign_str + custom_appsecret

            # 不去除空白字符 - 根据测试结果，保留原始字符串格式
            sign_str_after = sign_str

            # 生成32位MD5大写签名值
            md5_hash = hashlib.md5(sign_str_after.encode('utf-8')).hexdigest().upper()
            frappe.logger().debug(f"WDT定制接口签名生成完成: {md5_hash}")
            params["sign"] = md5_hash

            # 构建URL
            url_params = self._dict_to_url_params(params)
            final_url = custom_host + '?' + url_params

            frappe.logger().info(f"WDT定制接口请求: {custom_host}")
            frappe.logger().debug(f"请求参数: {params}")
            frappe.logger().debug(f"请求体: {body_json}")

            # 发送请求
            header = {
                "Content-Type": "application/json",
            }

            r = self.session.post(url=final_url, headers=header, data=body_json, timeout=30)

            # 检查HTTP状态码
            r.raise_for_status()

            # 解析响应（JSON格式）
            response_data = r.json()
            frappe.logger().debug(f"WDT定制接口响应: {response_data}")

            # 检查业务状态码
            if isinstance(response_data, dict):
                code = response_data.get("code")
                if code is not None and code != "":
                    error_msg = response_data.get("message", "未知业务错误")
                    frappe.logger().error(f"WDT定制接口业务错误: {error_msg}")
                    raise WDTAPIException(f"业务错误: {error_msg}", response_data)

            frappe.logger().info(f"WDT调用库存总量查询接口(定制): 货主={owner_no}, 仓库={warehouse_no}, 货位={is_position}")
            return response_data

        except Exception as e:
            frappe.logger().error(f"WDT库存总量查询接口(定制)调用失败: {e}")
            raise WDTAPIException(f"库存总量查询接口(定制)调用失败: {e}")



